using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using Tester.GuiActions;

namespace Tester.GuiActions.Actions
{
    public interface IMainMenuVisitor
    {
        void Visit(MainMenuManager.MainMenuItem value);
    }

    public class MainMenuCreateVisitor : IMainMenuVisitor
    {
        private MenuStrip _menu;

        private ToolStripItem _cuurentItem;

        public MenuStrip Menu
        {
            get
            {
                return _menu;
            }
        }

        public MainMenuCreateVisitor()
        {
            _cuurentItem = null; 
        }

        public void Visit(MainMenuManager.MainMenuItem value)
        {
            if (_cuurentItem == null)
            {
                if (_menu == null)
                {
                    _menu = new MenuStrip();
                }
                _cuurentItem = value.CreateMenuItem();
                _menu.Items.Add(_cuurentItem);
                value.Accept(this);
                _cuurentItem = null;
            }
            else
            {
                ToolStripItem temp = _cuurentItem;
                Debug.Assert(_cuurentItem != null);
                _cuurentItem = value.CreateMenuItem();
                ((ToolStripMenuItem)temp).DropDownItems.Add(_cuurentItem);
                value.Accept(this);
                _cuurentItem = temp;
            }
        }
    }

    public class MainMenuManager
    {
        public abstract class MainMenuItem
        {
            private IAction _action = null;
            private List<MainMenuItem> _subitems = null;
            private ToolStripMenuItem _menuItem = null;

            public abstract string Name
            {
                get;
            }

            public IAction Action
            {
                get
                {
                    return _action;
                }
                set
                {
                    _action = value;
                }
            }


            public List<MainMenuItem> Subitems
            {
                get
                {
                    return _subitems;
                }
            }


            public ToolStripMenuItem MenuItem
            {
                get
                {
                    return _menuItem;
                }
                set
                {
                    _menuItem = value;
                }
            }

            public void AddSubItem(MainMenuItem item)
            {
                _subitems = _subitems?? new List<MainMenuItem>();
                _subitems.Add(item);
            }

            public void Accept(IMainMenuVisitor visitor)
            {
                if (Subitems != null)
                {
                    foreach (MainMenuItem item in Subitems)
                    {
                        visitor.Visit(item);
                    }
                }
            }

            public abstract ToolStripItem CreateMenuItem();
        }

        public class MainMenuMenuItem : MainMenuItem
        {
            private String _name;
            private string _display;
            public string Display
            {
                get { return _display; }
                set { _display = value; }
            }

            public override string Name
            {
                get { return _name; }
            }

            public MainMenuMenuItem(string name, string display)
            {
                _name = name;
                _display = display;
            }

            public override ToolStripItem CreateMenuItem()
            {
                ToolStripMenuItem item = new ToolStripMenuItem();
                MenuItem = item;
                item.Text = Display;
                item.ToolTipText = 
                item.ToolTipText = Display;
                if (Action != null)
                {
                    item.ToolTipText = Action.Description;
                    item.Enabled = Action.Visible;
                    item.Click += Action.MainAction;
                    Action.CustomActionForMenu(this);
                    Action.UIChanged += delegate
                                                  {
                                                      item.Enabled = Action.Visible;
                                                      Action.CustomActionForMenu(this);
                                                  };
                }
                return item;
            }
        }

        public class MainMenuSeparator : MainMenuItem
        {
            private static int itemIndex = 0;

            private string _unicalName;

            public override string Name
            {
                get
                {
                    return _unicalName ?? (_unicalName = "$sep" + itemIndex++);
                }
            }

            public override ToolStripItem CreateMenuItem()
            {
                return new ToolStripSeparator();
            }
        }

        private MainMenuItem _rootItem = new MainMenuMenuItem("root","");

        private Dictionary<string, MainMenuItem> _allItems = new Dictionary<string, MainMenuItem>();

        public MainMenuItem RootItem
        {
            get
            {
                return _rootItem;
            }
        }

        public void AddSubitem(MainMenuItem item, MainMenuItem subitem)
        {
            _allItems.Add(subitem.Name, subitem);
            item.AddSubItem(subitem);
        }

        public void AddAction(string name, IAction action)
        {
            MainMenuItem item;
            if (_allItems.TryGetValue(name, out item))
            {
                item.Action = action; 
            }
        }

        public MenuStrip CreateMenu()
        {
            MainMenuCreateVisitor visitor = new MainMenuCreateVisitor();
            RootItem.Accept(visitor);
            return visitor.Menu;
        }
    }
}
